//+------------------------------------------------------------------+
//|                                                         6666.mq5 |
//|                                  Copyright 2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"

// 输入参数
input ulong      InpMagicNumber = 123456;     // EA魔术编号
input string     InpNoTradeTimeStart = "19:30"; // 不交易时间段开始(服务器时间)
input string     InpNoTradeTimeEnd = "23:30";   // 不交易时间段结束(服务器时间)
input int        InpMAPeriod1 = 5;            // 均线1周期
input int        InpMAPeriod2 = 8;           // 均线2周期
input int        InpMAPeriod3 = 10;           // 均线3周期
input int        InpMAPeriod4 = 11;           // 均线4周期
input int        InpMAPeriod5 = 13;           // 均线5周期
input int        InpMAPeriod6 = 15;           // 均线6周期
input ENUM_APPLIED_PRICE InpMAAppliedPrice = PRICE_CLOSE; // 均线应用价格
input ENUM_MA_METHOD InpMAMethod = MODE_SMA;  // 均线计算方法


// 全局变量
int maHandles[6];        // 均线指标句柄数组
double maValues[6];      // 均线值数组
datetime lastBarTime = 0;// 最后处理的K线时间
bool filterEnabled = false; // 持仓过滤开关状态
long chartID = 0;       // 图表ID
int buttonId = 1;       // 按钮ID

//+------------------------------------------------------------------+
//| 获取周期名称函数                                                 |
//+------------------------------------------------------------------+
string GetPeriodName()
{
   switch(_Period)
   {
      case PERIOD_M1:  return "M1";
      case PERIOD_M2:  return "M2";
      case PERIOD_M3:  return "M3";
      case PERIOD_M4:  return "M4";
      case PERIOD_M5:  return "M5";
      case PERIOD_M6:  return "M6";
      case PERIOD_M10: return "M10";
      case PERIOD_M12: return "M12";
      case PERIOD_M15: return "M15";
      case PERIOD_M20: return "M20";
      case PERIOD_M30: return "M30";
      case PERIOD_H1:  return "H1";
      case PERIOD_H2:  return "H2";
      case PERIOD_H3:  return "H3";
      case PERIOD_H4:  return "H4";
      case PERIOD_H6:  return "H6";
      case PERIOD_H8:  return "H8";
      case PERIOD_H12: return "H12";
      case PERIOD_D1:  return "D1";
      case PERIOD_W1:  return "W1";
      case PERIOD_MN1: return "MN1";
      default:         return "Unknown";
   }
}

//+------------------------------------------------------------------+
//| 平掉所有当前品种的持仓                                           |
//+------------------------------------------------------------------+
void CloseAllPositions()
{
   // 遍历所有持仓
   int total = PositionsTotal();
   for(int i = total-1; i >= 0; i--) // 从后往前遍历，因为平仓会改变持仓顺序
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == _Symbol)
      {
         // 获取持仓信息
         double volume = PositionGetDouble(POSITION_VOLUME);
         ENUM_POSITION_TYPE type = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         
         // 创建平仓请求
         MqlTradeRequest request;
         ZeroMemory(request);
         request.action = TRADE_ACTION_DEAL;
         request.position = ticket;
         request.symbol = _Symbol;
         request.volume = volume;
         request.deviation = 5;
         request.magic = InpMagicNumber;
         
         // 设置平仓方向
         if(type == POSITION_TYPE_BUY)
            request.price = SymbolInfoDouble(_Symbol, SYMBOL_BID);
         else
            request.price = SymbolInfoDouble(_Symbol, SYMBOL_ASK);
            
         request.type = (type == POSITION_TYPE_BUY) ? ORDER_TYPE_SELL : ORDER_TYPE_BUY;
         
         // 发送平仓请求
         MqlTradeResult result;
         ZeroMemory(result);
         if(OrderSend(request, result))
         {
            Print("成功平仓 #", ticket, " 手数: ", volume, " 类型: ", EnumToString(type));
         }
         else
         {
            Print("平仓失败 #", ticket, " 错误: ", GetLastError());
         }
      }
   }
}

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   // 打印当前品种、周期和魔术编号
   Print("EA初始化 - 魔术编号: ", InpMagicNumber);
   Print("当前交易品种: ", _Symbol, " | 当前周期: ", GetPeriodName());
   Print("均线参数: ", InpMAPeriod1, ", ", InpMAPeriod2, ", ", InpMAPeriod3, ", ",
         InpMAPeriod4, ", ", InpMAPeriod5, ", ", InpMAPeriod6);
   Print("不交易时间段: ", InpNoTradeTimeStart, " 至 ", InpNoTradeTimeEnd);
   // 创建均线指标
   maHandles[0] = iMA(_Symbol, _Period, InpMAPeriod1, 0, InpMAMethod, InpMAAppliedPrice);
   maHandles[1] = iMA(_Symbol, _Period, InpMAPeriod2, 0, InpMAMethod, InpMAAppliedPrice);
   maHandles[2] = iMA(_Symbol, _Period, InpMAPeriod3, 0, InpMAMethod, InpMAAppliedPrice);
   maHandles[3] = iMA(_Symbol, _Period, InpMAPeriod4, 0, InpMAMethod, InpMAAppliedPrice);
   maHandles[4] = iMA(_Symbol, _Period, InpMAPeriod5, 0, InpMAMethod, InpMAAppliedPrice);
   maHandles[5] = iMA(_Symbol, _Period, InpMAPeriod6, 0, InpMAMethod, InpMAAppliedPrice);
   
   // 检查指标是否创建成功
   for(int i = 0; i < 6; i++)
   {
      if(maHandles[i] == INVALID_HANDLE)
      {
         Print("创建MA指标失败 #", i+1, " (周期: ", GetMAPeriod(i), ")");
         return(INIT_FAILED);
      }
   }

   // 创建按钮
   chartID = ChartID();
   CreateButton();
   
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| 获取指定索引的均线周期                                           |
//+------------------------------------------------------------------+
int GetMAPeriod(int index)
{
   switch(index)
   {
      case 0: return InpMAPeriod1;
      case 1: return InpMAPeriod2;
      case 2: return InpMAPeriod3;
      case 3: return InpMAPeriod4;
      case 4: return InpMAPeriod5;
      case 5: return InpMAPeriod6;
      default: return 0;
   }
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   // 释放指标句柄
   for(int i = 0; i < 6; i++)
   {
      if(maHandles[i] != INVALID_HANDLE)
      {
         IndicatorRelease(maHandles[i]);
      }
   }

   // 删除按钮
   ObjectDelete(chartID, "FilterButton");

   Print("EA已卸载，魔术编号: ", InpMagicNumber);
}
//+------------------------------------------------------------------+
//| 创建按钮函数                                                     |
//+------------------------------------------------------------------+
void CreateButton()
{
   // 创建按钮对象
   if(!ObjectCreate(chartID, "FilterButton", OBJ_BUTTON, 0, 0, 0))
   {
      Print("创建按钮失败: ", GetLastError());
      return;
   }
   
   // 设置按钮属性
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_XDISTANCE, 25);
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_YDISTANCE, 50);
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_XSIZE, 200);
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_YSIZE, 30);
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_CORNER, CORNER_LEFT_UPPER);
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_BGCOLOR, clrGreen);
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_COLOR, clrWhite);
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_BORDER_COLOR, clrBlack);
   ObjectSetString(chartID, "FilterButton", OBJPROP_TEXT, "关，程序正常运行");
   
   // 启用按钮接收点击事件
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_SELECTABLE, false);
   ObjectSetInteger(chartID, "FilterButton", OBJPROP_SELECTED, false);
   
   ChartRedraw(chartID);
}

//+------------------------------------------------------------------+
//| 处理图表点击事件                                                 |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   // 检查是否是对象点击事件
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      // 检查是否点击了我们的按钮
      if(sparam == "FilterButton")
      {
         // 切换开关状态
         filterEnabled = !filterEnabled;
         
         // 更新按钮显示
         if(filterEnabled)
         {
            ObjectSetString(chartID, "FilterButton", OBJPROP_TEXT, "开，盈利后出局");
            ObjectSetInteger(chartID, "FilterButton", OBJPROP_BGCOLOR, clrGray);
         }
         else
         {
            ObjectSetString(chartID, "FilterButton", OBJPROP_TEXT, "关，程序正常运行");
            ObjectSetInteger(chartID, "FilterButton", OBJPROP_BGCOLOR, clrGreen);
         }
         
         ChartRedraw(chartID);
      }
   }
}

//+------------------------------------------------------------------+
//| 检查持仓过滤条件                                                 |
//+------------------------------------------------------------------+
bool CheckPositionFilter()
{
   // 如果过滤关闭，直接返回true继续执行
   if(!filterEnabled) return true;
   
   // 检查当前品种是否有持仓
   int total = PositionsTotal();
   string symbol = Symbol();
   
   for(int i = 0; i < total; i++)
   {
      if(PositionGetSymbol(i) == symbol)
      {
         // 找到当前品种的持仓，返回true继续执行
         return true;
      }
   }
   
   // 没有找到当前品种的持仓，返回false退出OnTick
   return false;
}

//+------------------------------------------------------------------+
//| 获取均线值函数                                                   |
//+------------------------------------------------------------------+
bool GetMAValues(int shift)
{
   // 复制均线数据
   for(int i = 0; i < 6; i++)
   {
      double buf[1];
      if(CopyBuffer(maHandles[i], 0, shift, 1, buf) != 1)
      {
         Print("复制MA数据失败 #", i+1, " (周期: ", GetMAPeriod(i), ")");
         return false;
      }
      maValues[i] = buf[0];
   }
   return true;
}

//+------------------------------------------------------------------+
//| 检查均线趋势函数                                                 |
//| 返回值:                                                          |
//|  1 - 多头排列 (MA1>MA2>MA3>MA4>MA5>MA6)                         |
//|  0 - 空头排列 (MA6>MA5>MA4>MA3>MA2>MA1)                         |
//| -1 - 其他情况或错误                                              |
//+------------------------------------------------------------------+
int CheckMATrend(bool checkNewBar = true)
{
   // 如果要求检查新K线
   if(checkNewBar)
   {
      datetime currentBarTime = iTime(_Symbol, _Period, 0);
      if(lastBarTime == currentBarTime)
         return -1;
      lastBarTime = currentBarTime;
   }
   
   // 获取前一根K线的均线值
   if(!GetMAValues(1)) // 1表示前一根K线
      return -1;
   
   // 检查多头排列 (MA1>MA2>MA3>MA4>MA5>MA6)
   if(maValues[0] > maValues[1] && maValues[1] > maValues[2] && 
      maValues[2] > maValues[3] && maValues[3] > maValues[4] && maValues[4] > maValues[5])
   {
      return 1;
   }
   // 检查空头排列 (MA6>MA5>MA4>MA3>MA2>MA1)
   else if(maValues[5] > maValues[4] && maValues[4] > maValues[3] && 
           maValues[3] > maValues[2] && maValues[2] > maValues[1] && maValues[1] > maValues[0])
   {
      return 0;
   }
   
   return -1;
}


//+------------------------------------------------------------------+
//| 检查是否在不交易时间段且没有持仓                                 |
//+------------------------------------------------------------------+
bool CheckTradingTime()
{
   // 获取当前服务器时间
   MqlDateTime timeStruct;
   TimeCurrent(timeStruct);
   int currentMinutes = timeStruct.hour * 60 + timeStruct.min;
   string currentTimeStr = StringFormat("%02d:%02d", timeStruct.hour, timeStruct.min);
   
   // 解析开始和结束时间
   string startParts[], endParts[];
   StringSplit(InpNoTradeTimeStart, ':', startParts);
   StringSplit(InpNoTradeTimeEnd, ':', endParts);
   
   int startMinutes = (int)StringToInteger(startParts[0]) * 60 + (int)StringToInteger(startParts[1]);
   int endMinutes = (int)StringToInteger(endParts[0]) * 60 + (int)StringToInteger(endParts[1]);
   
   // 调试打印
   Print("当前时间: ", currentTimeStr, " (", currentMinutes, "分钟) | 不交易时间段: ", 
         InpNoTradeTimeStart, "-", InpNoTradeTimeEnd, " (", startMinutes, "-", endMinutes, "分钟)");
   Print("持仓数量: ", PositionsTotal());
   
   // 检查是否在不交易时间段内（处理跨天情况）
   bool inNoTradePeriod = false;
   
   if(startMinutes < endMinutes) 
   {
      // 普通时间段（不跨天）
      inNoTradePeriod = (currentMinutes >= startMinutes && currentMinutes <= endMinutes);
   }
   else 
   {
      // 跨天时间段（如23:30-6:00）
      inNoTradePeriod = (currentMinutes >= startMinutes || currentMinutes <= endMinutes);
   }
   
   if(inNoTradePeriod)
   {
      if(PositionsTotal() == 0)
      {
         Print("处于不交易时间段且没有持仓，退出OnTick()");
         return false;
      }
      else
      {
         Print("处于不交易时间段但有持仓，继续执行");
      }
   }
   else
   {
      Print("不在不交易时间段内，继续执行");
   }
   return true;
}

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
{

   // 检查当前持仓情况
   //CheckCurrentPositions();
   
   // 检查持仓过滤条件
   if(!CheckPositionFilter()) return;
   // 这里继续原有的OnTick逻辑

   // 检查交易时间，如果不满足条件则退出
   if(!CheckTradingTime())
   {
      Print("CheckTradingTime返回false，退出OnTick()");
      return;
   }
   
   // 获取趋势状态
   int trend = CheckMATrend();
   
   // 打印结果
   if(trend != -1)
   {
      Print("魔术编号: ", InpMagicNumber, " | 趋势: ", 
            (trend == 1 ? "多头" : (trend == 0 ? "空头" : "无趋势")), 
            " | 均线值: ", ArrayToString(maValues));

   }

   // 调用马丁网格交易函数
   //MartinGridTrading();

}

//+------------------------------------------------------------------+
//| 将数组转换为字符串                                               |
//+------------------------------------------------------------------+
string ArrayToString(const double &arr[])
{
   string result = "";
   for(int i = 0; i < ArraySize(arr); i++)
   {
      if(i > 0) result += ", ";
      result += DoubleToString(arr[i], _Digits);
   }
   return result;
}
//+------------------------------------------------------------------+